package com.hmdp.utils;

import cn.hutool.core.lang.UUID;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;

import java.util.Collections;
import java.util.concurrent.TimeUnit;

public class SimpleRedisLock implements ILock{

    /**
     * 锁的名字
     */
    private String name;
    private StringRedisTemplate stringRedisTemplate;

    public SimpleRedisLock(String name, StringRedisTemplate stringRedisTemplate) {
        this.name = name;
        this.stringRedisTemplate = stringRedisTemplate;
    }

    private static final String KEY_PREFIX = "lock:";
    private static final String ID_PREFIX = UUID.randomUUID().toString(true) + "-";

    // 定义lua脚本的静态代码块，启动时自动执行
    private static final DefaultRedisScript<Long> UNLOCK_LUA;
    static {
        UNLOCK_LUA = new DefaultRedisScript<Long>();
        UNLOCK_LUA.setLocation(new ClassPathResource("lua/unlock.lua"));
        UNLOCK_LUA.setResultType(Long.class);
    }

    /**
     * 获取锁
     * @param timeOutSecKill
     */
    @Override
    public boolean tryLock(Long timeOutSecKill) {
        // 获取当前线程的id
        String threadId = ID_PREFIX + Thread.currentThread().getId();
        // 将锁对象存入redis中
        Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(
                KEY_PREFIX + name, threadId, timeOutSecKill, TimeUnit.SECONDS);
        // 防止自动拆箱造成的空指针异常
        return Boolean.TRUE.equals(result);
    }

    /**
     * 释放锁
     * 基于lua脚本修改释放锁的逻辑，解决误删的问题
     */
    @Override
    public void unLock() {
        // 调用lua脚本
        // 保证判断和释放一同执行，避免出现线程阻塞的现象
        stringRedisTemplate.execute(
                UNLOCK_LUA,
                Collections.singletonList(KEY_PREFIX + name),
                ID_PREFIX + Thread.currentThread().getId());
    }

  /*  /**
     * 释放锁
     *
     *//*
    @Override
    public void unLock() {
        // 对该线程标识进行判断 - 解决redis分布式锁的误删问题
        // 获取当前线程的id
        String threadId = ID_PREFIX + Thread.currentThread().getId();
        String currentId = stringRedisTemplate.opsForValue().get(KEY_PREFIX + name);
        if(threadId.equals(currentId)){
            // 线程标识一致
            // 释放锁
            stringRedisTemplate.delete(KEY_PREFIX + name);
        }
    }*/
}
